﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;

namespace Client
{
    public sealed class ServerInformation
    {
        public HostName Name;
        public String AccessCode;
    }
    public sealed class ServerFoundArgs
    {
        public List<ServerInformation> ServerNames;
    }
    public delegate void ServerFoundHandler(object sender, ServerFoundArgs e);
    public delegate void FileTransferCompletedHandler(object sender,object e);
    public class ClientController
    {
        public bool IsConnected;
        private bool isConnecting;
        public String accessCode;
        private DatagramSocket udpSocket, udpSendSocket;

        private const int BroadcastData = 0;
        private const int RequestFile = 1;
        private const int FileSummary = 2;
        private const int FilePart = 3;
        private const int EndFile = 4;

        public event ServerFoundHandler ServerFound;
        public event FileTransferCompletedHandler FileTransferCompleted;
        public ClientController()
        {
            udpSocket = new DatagramSocket();
        }

        async void udpSocket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
        {

            DataReader reader = args.GetDataReader();
            int dataType = reader.ReadInt32();
            if (dataType == FilePart)
            {
                long dataSize1 = reader.ReadInt64();
                byte[] data1 = new byte[dataSize1];
                reader.ReadBytes(data1);
                RequestFileByAccessCode(accessCode,1024);
            }
            else if (dataType == EndFile)
            {
                FileTransferCompleted(this,null);
            }
            else if (dataType == 0)
            {
                if (isConnecting)
                    return;
                isConnecting = true;
                long dataSize1 = reader.ReadInt64();
                byte[] data1 = new byte[dataSize1];
                reader.ReadBytes(data1);
                long dataSize2 = reader.ReadInt64();
                byte[] data2 = new byte[dataSize2];
                reader.ReadBytes(data2);

                string ip = System.Text.Encoding.UTF8.GetString(data1, 0, data1.Length);
                string content = System.Text.Encoding.UTF8.GetString(data2, 0, data2.Length);
                ServerFoundArgs foundargs = new ServerFoundArgs();
                foundargs.ServerNames = new List<ServerInformation>();
                foundargs.ServerNames.Add(new ServerInformation()
                {
                    Name = args.RemoteAddress,//new HostName(ip),
                    AccessCode = content
                });
                ServerFound(this, foundargs);
                //await udpSocket.ConnectAsync(new HostName("127.0.0.1"), "4455");
                //ReplyBroadcastService(content);
            }
        }

        public async Task<bool> ConnectToServer(ServerInformation info)
        {
            if (udpSendSocket != null)
            {
                udpSendSocket.Dispose();
                udpSendSocket = null;
            }
            udpSendSocket = new DatagramSocket();
            await udpSendSocket.ConnectAsync(info.Name, "4455");
            await RequestFileByAccessCode(info.AccessCode,0);
            accessCode = info.AccessCode;
            return true;
        }

        async Task<bool> RequestFileByAccessCode(string accesscode, long position)
        {
            DataWriter writer = new DataWriter(udpSendSocket.OutputStream);
            byte[] data = System.Text.Encoding.UTF8.GetBytes(accesscode);
            int datatype = RequestFile;
            writer.WriteInt32(datatype);
            writer.WriteInt64(data.Length);
            writer.WriteBytes(data);
            writer.WriteInt64(position);
            await writer.StoreAsync();
            return true;
        }

        public void StartFindServer(String accessCode)
        {
            udpSocket.MessageReceived += udpSocket_MessageReceived;
            udpSocket.BindServiceNameAsync("4455");
        }

        private void Broadcast()
        {

        }

    }
}
